﻿using System;
using System.Collections.Generic;
using System.Reflection;
using MugenInjection.Interface.Components;

namespace MugenInjection.Activators
{
    /// <summary>
    /// Represents the activator that use reflection to activate object.
    /// </summary>
    public class ReflectionActivator : ActivatorBase
    {
        #region Implementation of IActivator

        /// <summary>
        ///     Creates a new instance of the specified service.
        /// </summary>
        /// <param name="constructorInfo">
        ///     The specified <see cref="ConstructorInfo" />.
        /// </param>
        protected override object Activate(ConstructorInfo constructorInfo)
        {
            return constructorInfo.Invoke(CurrentContext.Injector
                                                        .Components.BindingActivatorComponent
                                                        .GetParameters(constructorInfo, CurrentContext));
        }

        /// <summary>
        ///     Injects values into properties, fields, methods in the specified object.
        /// </summary>
        /// <param name="targetType">
        ///     The specified target <see cref="Type" />.
        /// </param>
        /// <param name="target">The specified target for inject.</param>
        protected override void Inject<T>(Type targetType, ref T target)
        {
            Type attributeForInject = CurrentContext.Injector.Settings.AttributeForInject;
            if (!IsHasValuesToInject(targetType, attributeForInject)) return;
            IBindingActivatorComponent activatorComponent = CurrentContext.Injector.Components.BindingActivatorComponent;
            
            IList<PropertyInfo> propertiesToInject = GetPropertiesToInject(targetType, attributeForInject);
            if (propertiesToInject.Count > 0)
            {
                for (int i = 0; i < propertiesToInject.Count; i++)
                {
                    PropertyInfo propertyInfo = propertiesToInject[i];
                    propertyInfo.SetValue(target, activatorComponent.GetParameter(propertyInfo, CurrentContext), null);
                }
            }
            
            IList<MethodInfo> methodsToInject = GetMethodsToInject(targetType, attributeForInject);
            if (methodsToInject.Count > 0)
            {
                for (int i = 0; i < methodsToInject.Count; i++)
                {
                    MethodInfo methodInfo = methodsToInject[i];
                    methodInfo.Invoke(target, activatorComponent.GetParameters(methodInfo, CurrentContext));
                }
            }
        }

        #endregion
    }
}